<template>
  <div
    :style="{
      height: currentOptions.height + 'px',
      width: currentOptions.width + 'px',
      background: currentOptions.background,
    }"
    id="map"
  />
</template>

<script>
import { Scene, PointLayer, LineLayer, PolygonLayer } from "@antv/l7";
import { DrillDownLayer } from "@antv/l7-district";
import { Mapbox } from "@antv/l7-maps";
export default {
  name: "chinaMap_1",
  data() {
    return {
      map: null,
      drillLayer: null,
      flyLayer: null,
      currentOptions: {
        width: 800,
        height: 500,
        background: "#000",
        center: [106.530635, 29.544606],
        pitch: 5,
        mapColor: ["#B8E1FF"],
      },
      pointLayerList: [],
      polygonLayerList: [],
      currnetCode: 100000,
    };
  },
  props: {
    options: {
      type: Object,
      default: () => {
        return {};
      },
    },
    pointArr: {
      type: Array,
      default: () => {
        return [];
      },
    },
    flyLineArr: {
      type: Array,
      default: () => {
        return [];
      },
    },
    streetData: {
      type: Object,
      default: () => {
        return {};
      },
    },
  },
  methods: {
    initMap() {
      const { currentOptions } = this;
      if (this.map) {
        this.map.destroy();
      }
      this.map = new Scene({
        id: "map",
        map: new Mapbox({
          style: "blank",
          center: currentOptions.center,
          pitch: currentOptions.pitch,
          zoom: 3,
          // scrollZoom: false,
        }),
      });
      this.map.on("loaded", () => {
        if (this.drillLayer) {
          this.drillLayer.destroy();
          this.drillLayer = null;
        }
        this.drillLayer = new DrillDownLayer(this.map, {
          data: [],
          viewStart: "Country",
          viewEnd: "County",
          fill: {
            color: {
              field: "NAME_CHN",
              values: currentOptions.mapColor,
            },
          },
          drillUpEvent: (props) => {
            if (props.to === "Province") {
              const formatPointArr = this.pointArr.filter((item) => {
                return Math.abs(item.adCode - this.currnetCode) >= 10000
                  ? false
                  : true;
              });
              this.initPoint(formatPointArr);
            } else if (props.to === "Country") {
              this.initPoint(this.pointArr);
            }
            if (this.polygonLayerList.length) {
              this.polygonLayerList.map((item) => {
                this.map.removeLayer(item);
              });
              this.polygonLayerList = [];
            }
          },
          drillDownEvent: (props) => {
            const formatPointArr = this.pointArr.filter((item) => {
              return Math.abs(item.adCode - props.adcode) >= 8000
                ? false
                : true;
            });
            this.initPoint(formatPointArr);
            this.currnetCode = props.adcode;
          },
          popup: {
            enable: true,
            Html: (props) => {
              return `<span style="color: #fff;">${props.NAME_CHN}</span>`;
            },
          },
        });

        this.drillLayer.countyLayer.on("click", (e) => {
          this.drillLayer.countyLayer.hide();
          const adcode = e.feature.properties.adcode;
          this.drillLayer.countyLayer.updateDistrict(adcode);
          this.drillLayer.countyLayer.fillLayer.fitBounds();
          const formatPointArr = this.pointArr.filter((item) => {
            return item.adCode === adcode;
          });
          this.initPoint(formatPointArr);
          this.initStreet(this.streetData, adcode);
        });
      });
    },
    initPoint(pointArr) {
      if (this.pointLayerList) {
        this.pointLayerList.map((item) => {
          this.map.removeLayer(item);
        });
        this.pointLayerList = [];
      }

      if (!pointArr.length) return;
      let animateStatus = false;
      for (let i = 0; i < pointArr.length; i++) {
        if (pointArr[i].animate && pointArr[i].animate === true) {
          animateStatus = true;
          break;
        }
      }
      const pointLayer = new PointLayer({ zIndex: 5 })
        .source(pointArr, {
          parser: {
            type: "json",
            x: "lng",
            y: "lat",
          },
        })
        .shape("type", (type) => {
          return type || "circle"; //'circle'| 'square'| 'hexagon'| 'triangle'| 'pentagon'| 'octogon'| 'hexagram'| 'rhombus'| 'vesica';
        })
        .animate(animateStatus)
        .size("size", (size) => {
          return size || 10;
        })
        .color("color", (color) => {
          return color || "red";
        });

      const pointLabelLayer = new PointLayer({ zIndex: 5 })
        .source(pointArr, {
          parser: {
            type: "json",
            x: "lng",
            y: "lat",
          },
        })
        .shape("label", "text")
        .size("labelSize", (labelSize) => {
          return labelSize || 10;
        })
        .color("labelColor", (labelColor) => {
          return labelColor || "red";
        })
        .style({
          textAnchor: "center", // 文本相对锚点的位置 center|left|right|top|bottom|top-left
          textOffset: {
            field: "textOffset",
            value: (textOffset) => {
              return textOffset || [0, 50];
            },
          }, // 文本相对锚点的偏移量 [水平, 垂直]
          spacing: 2, // 字符间距
          padding: [1, 1], // 文本包围盒 padding [水平，垂直]，影响碰撞检测结果，避免相邻文本靠的太近
          strokeWidth: 1, // 描边宽度
          strokeOpacity: 1.0,
        });
      this.map.addLayer(pointLayer);
      this.map.addLayer(pointLabelLayer);
      this.pointLayerList.push(pointLayer);
      this.pointLayerList.push(pointLabelLayer);
    },
    initFlyLine(flyLineArr) {
      if (this.flyLayer) {
        this.map.removeLayer(this.flyLayer);
        this.flyLayer = null;
      }
      if (!flyLineArr.length) return;
      this.flyLayer = new LineLayer({ zIndex: 5 })
        .source(flyLineArr, {
          parser: {
            type: "json",
            x: "fromLng",
            y: "fromLat",
            x1: "toLng",
            y1: "toLat",
          },
        })
        .size("size", (size) => {
          return size || 6;
        })
        .color("color", (color) => {
          return color || "red";
        })
        .shape("arc3d")
        .style({
          opacity: 0.8,
        })
        .animate({
          enable: true,
          interval: 1,
          duration: 2,
          trailLength: 0.8,
        });
      this.map.addLayer(this.flyLayer);
    },
    initStreet(streetData, adcode) {
      if (!Object.keys(streetData).length) return;
      let newStreetData = {
        type: streetData.type,
        features: [],
      };
      let streetLabelLayer = [];
      streetData.features.map((item) => {
        if (parseInt(item.properties.adcode / 1000) === adcode) {
          newStreetData.features.push(item);
          streetLabelLayer.push({
            name: item.properties.name,
            labelSize: item.properties.labelSize || 12,
            labelColor: item.properties.labelColor || "#000",
            ...this.getPointsCenter(item.geometry.coordinates[0]),
          });
        }
      });
      const streetPolygonLayer = new PolygonLayer({ zIndex: 5 })
        .source(newStreetData)
        .color("fill", (fill) => {
          return fill || "#000";
        })
        .shape("fill");
      const streetLineLayer = new LineLayer({
        zIndex: 5,
      })
        .source(newStreetData)
        .color("stroke", (stroke) => {
          return stroke || "#fff";
        })
        .active(true)
        .size(1)
        .style({
          lineType: "dash",
          dashArray: [2, 2],
        });
      const streetPointLayer = new PointLayer({ zIndex: 5 })
        .source(streetLabelLayer, {
          parser: {
            type: "json",
            x: "lng",
            y: "lat",
          },
        })
        .shape("name", "text")
        .size("labelSize", (labelSize) => {
          return labelSize || 12;
        })
        .color("labelColor", (labelColor) => {
          return labelColor || "#000";
        })
        .style({
          textAnchor: "center", // 文本相对锚点的位置 center|left|right|top|bottom|top-left
          textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直]
          spacing: 2, // 字符间距
          padding: [1, 1], // 文本包围盒 padding [水平，垂直]，影响碰撞检测结果，避免相邻文本靠的太近
          stroke: "#ffffff", // 描边颜色
          strokeWidth: 0.3, // 描边宽度
        });
      this.map.addLayer(streetPolygonLayer);
      this.map.addLayer(streetLineLayer);
      this.map.addLayer(streetPointLayer);
      this.polygonLayerList = [
        streetPolygonLayer,
        streetLineLayer,
        streetPointLayer,
      ];
    },
    getPointsCenter(points) {
      let point_num = points.length; //坐标点个数
      let X = 0,
        Y = 0,
        Z = 0;
      for (let i = 0; i < points.length; i++) {
        if (!points[i].length) {
          continue;
        }
        let point = points[i];
        var lat, lng, x, y, z;
        lat = (parseFloat(point[1]) * Math.PI) / 180;
        lng = (parseFloat(point[0]) * Math.PI) / 180;
        x = Math.cos(lat) * Math.cos(lng);
        y = Math.cos(lat) * Math.sin(lng);
        z = Math.sin(lat);
        X += x;
        Y += y;
        Z += z;
      }
      X = X / point_num;
      Y = Y / point_num;
      Z = Z / point_num;
      let tmp_lng = Math.atan2(Y, X);
      let tmp_lat = Math.atan2(Z, Math.sqrt(X * X + Y * Y));
      return {
        lng: (tmp_lng * 180) / Math.PI,
        lat: (tmp_lat * 180) / Math.PI,
      };
    },
  },
  mounted() {},
  watch: {
    options: {
      immediate: true,
      deep: true,
      handler: function (val) {
        if (Object.keys(val).length) {
          this.currentOptions.width = val.width
            ? val.width
            : this.currentOptions.width;
          this.currentOptions.height = val.height
            ? val.height
            : this.currentOptions.height;
          this.currentOptions.background = val.background
            ? val.background
            : this.currentOptions.background;
          this.currentOptions.center = val.center
            ? val.center
            : this.currentOptions.center;
          this.currentOptions.pitch = val.pitch
            ? val.pitch
            : this.currentOptions.pitch;
          this.currentOptions.mapColor = val.mapColor
            ? val.mapColor
            : this.currentOptions.mapColor;
          this.$nextTick(() => {
            this.initMap();
          });
        }
      },
    },
    pointArr: {
      immediate: true,
      deep: true,
      handler: function (val) {
        this.$nextTick(() => {
          this.initPoint(val);
        });
      },
    },
    flyLineArr: {
      immediate: true,
      deep: true,
      handler: function (val) {
        this.$nextTick(() => {
          this.initFlyLine(val);
        });
      },
    },
  },
};
</script>

<style scoped lang="scss">
#map {
  justify-content: center;
  position: relative;

  ::v-deep .l7-control-logo-link {
    display: none;
  }

  ::v-deep .amap-copyright {
    display: none !important;
  }

  ::v-deep .l7-popup-content {
    background: rgba(0, 0, 0, 0.3);
  }

  ::v-deep .l7-popup-tip {
    border-top-color: rgba(0, 0, 0, 0.3);
  }
}
</style>
